package com.netx.data;
import java.util.Map;
import java.util.List;

import com.netx.generics.basic.ValidationException;
import com.netx.generics.collections.ImmutableList;
import com.netx.generics.collections.ImmutableMap;


public abstract class MetaData {

	private final String _name;
	private final Database _database;
	//private final UnmodifiableList _constraints;
	private ImmutableMap<String,Field> _fields;
	private Field[] _primaryKeyFields;

	MetaData(String iName, List<String[]> iConstraints, Database iDatabase) {
		_name = iName;
		//_constraints = new UnmodifiableList(iConstraints);
		_database = iDatabase;
		_fields = null;
		_primaryKeyFields = null;
	}
	
	public final String getName() {
		return _name;
	}
	
	public final String toString() {
		return getName();
	}
	
	public Field[] getPrimaryKey() {
		return _primaryKeyFields;
	}

	public Field getField(String name) {
		return (Field)_fields.get(name.toLowerCase());
	}

	public ImmutableMap<String,Field> getFields() {
		return _fields;
	}
	
	public Database getDatabase() {
		return _database;
	}
	
	// For Connection:
	abstract ImmutableList<DataSink> getReplicationSinks();

	// For DatabaseAnalyzer:
	void setFields(Map<String,Field> fields, List<Field> pkFields) {
		_fields = new ImmutableMap<String,Field>(fields);
		_primaryKeyFields = pkFields.toArray(new Field[0]);
	}

	// For Entity:
	String valueToSQL(Value v) {
		Field field = getField(v.getFieldName());
		if(field == null) {
			throw new ValidationException("invalid field name: "+v.getFieldName());
		}
		Object value = v.getValue();
		if(value == null) {
			if(field.isRequired()) {
				throw new ValidationException("required data field: "+v.getFieldName());
			}
			// No need to validate null values:
			return "NULL";
		}
		else {
			try {
				return field.toSQL(value);
			}
			catch(IllegalArgumentException iae) {
				throw new ValidationException("in field \""+field.getName()+"\": illegal value \""+value+"\"");
			}
			catch(ClassCastException cce) {
				throw new ValidationException("in field \""+field.getName()+"\": expected "+field.getType()+" value, found "+value.getClass().getName());
			}
			catch(IndexOutOfBoundsException iobe) {
				throw new ValidationException("in field \""+field.getName()+"\": value is too large. Expected length of "+iobe.getMessage()+", found "+value.toString().length());
			}
		}
	}
}
